home *** CD-ROM | disk | FTP | other *** search
/ Developer CD Series 2000 January: Mac OS SDK / Dev.CD Jan 00 SDK2.toast / Development Kits / Hardware / Mac OS USB DDK v1.3f3 / Examples / USBSampleStorageDriver / SampleStorageDriver.c < prev    next >
Encoding:
C/C++ Source or Header  |  1999-08-24  |  38.6 KB  |  1,150 lines  |  [TEXT/MPS ]

  1. /*
  2.     File:        SampleStorageDriver.c
  3.  
  4.     Contains:    All functions for the Class driverto access and control the device
  5.  
  6.     Version:        1.1
  7.  
  8.     Copyright:    © 1998-1999 by Apple Computer, Inc., all rights reserved.
  9.  
  10. */
  11.  
  12.  
  13. /*~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
  14.     includes
  15.   ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~*/
  16. #include <Devices.h>
  17. #include <DriverServices.h>
  18. #include <Interrupts.h>
  19. #include <LowMem.h>
  20. #include <Folders.h>
  21. #include <MacTypes.h>
  22. #include <CodeFragments.h>
  23.  
  24. #include <USB.h>
  25.  
  26. #include "SampleStorageDriverAPI.h"
  27. #include "SampleStorageDeviceID.h"
  28. #include "SampleStorageDriver.h"
  29.  
  30. extern TheStorageClassDispatchTable;
  31.  
  32. enum
  33. {
  34.     kCString = 0,                // StateStr, USBStatusStr selector
  35.     kPString                        // StateStr, USBStatusStr selector
  36. };
  37.  
  38. /*~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
  39.     globals
  40.   ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~*/
  41. static             Boolean                            gBeenThereDoneThat = false;    // Flag indicating if this driver has been called before
  42.  
  43. static            Boolean                            gConfigured = false;                // No calls to dispatch table until this is true.
  44.  
  45. static            UInt32                            gConfigureStatus;                    // Current state of cinfiguration
  46.  
  47. static            Boolean                            gOKToRemoval = true;            // Used in StorageClassDriverNotifyProc to prevent removal by expert
  48.  
  49. static struct    StorageClassInfo                gStorageClassInfo;                // Holds all of the common items
  50.     
  51. static struct    StorageClassTransactionPB    gInterruptPB;                        // Used only for the interrupt pipe
  52.  
  53. static struct    StorageClassStatusPB            gGetStatusPB;                        // Used only for the USB Get Status request
  54.  
  55. static struct    StorageClassControlPB        gControlPB;                            // Used only for aborting a R/W transaction
  56.  
  57. static struct    StorageClassTransactionPB    gCommandPB;                            // Used only by StorageClassDriverExecuteCommand
  58.  
  59. /*~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
  60.     prototypes
  61.   ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~*/
  62.  
  63. static void InitParamBlock(USBDeviceRef theDeviceRef, USBPB* paramblock);
  64.  
  65. static Boolean    ImmediateError(OSStatus err);
  66.  
  67. static void    StorageDeviceConfigureCompletion(USBPB* pb);
  68.  
  69. static void    StorageDeviceInitiateConfiguration(USBPB* pb);
  70.  
  71. static OSStatus StorageClassDriverGetStatus( StorageStatusPBPtr statusPBPtr );
  72.  
  73. static OSStatus StorageClassDriverAbortTransaction( StorageControlPBPtr controlPBPtr );
  74.  
  75. // Completion routines
  76.  
  77. static void ReadBlockCompletion(USBPB* usbPB);
  78.  
  79. static void WriteBlockCompletion(USBPB* usbPB);
  80.  
  81. static void ExecuteCommandCompletion(USBPB* usbPB);
  82.  
  83. static void ExecuteBufferedCommandCompletion(USBPB* usbPB);
  84.  
  85. static void GetStatusCompletion(USBPB* usbPB);
  86.  
  87. static void AbortTransactionCompletion(USBPB* usbPB);
  88.  
  89. //****************************************************************************************************
  90.  
  91. #if DEBUG
  92.  
  93. static void
  94. HexStr(    unsigned long    v,
  95.             unsigned char    *p )
  96. {
  97.     int    shift;
  98.     
  99.     for ( shift = 32-4; shift >= 0; shift -= 4 )
  100.     {
  101.         char c = (v >> shift) & 0x0F;
  102.         *p++ = c + (c > 9? ('A'-10): '0');
  103.     }
  104. }
  105.  
  106. static unsigned char *
  107. USBStatusStr(    OSStatus    usbStatus,
  108.                     int        kind )
  109. {
  110.     unsigned char *p;
  111.  
  112.     switch ( usbStatus )
  113.     {
  114.         case    kUSBInternalErr:                    p = "\p" kStrStorageClass "Internal error"; break;
  115.         case    kUSBUnknownDeviceErr:            p = "\p" kStrStorageClass "Unknown device"; break;
  116.         case    kUSBUnknownPipeErr:                 p = "\p" kStrStorageClass "Unknown pipe"; break;
  117.         case    kUSBTooManyPipesErr:                p = "\p" kStrStorageClass "Too many pipes"; break;
  118.         case    kUSBIncorrectTypeErr:            p = "\p" kStrStorageClass "Incorrect type"; break;
  119.         case    kUSBRqErr:                            p = "\p" kStrStorageClass "Request error"; break;
  120.         case    kUSBUnknownRequestErr:            p = "\p" kStrStorageClass "Unknown request"; break;
  121.         case    kUSBTooManyTransactionsErr:    p = "\p" kStrStorageClass "Too many transactions"; break;
  122.         case    kUSBAlreadyOpenErr:                p = "\p" kStrStorageClass "Already open"; break;
  123.         case    kUSBNoDeviceErr:                    p = "\p" kStrStorageClass "No device"; break;
  124.         case    kUSBDeviceErr:                        p = "\p" kStrStorageClass "Device error"; break;
  125.         case    kUSBOutOfMemoryErr:                p = "\p" kStrStorageClass "Out of memory"; break;
  126.         case    kUSBNotFound:                        p = "\p" kStrStorageClass "USB Not found"; break;
  127.         case    kUSBLinkErr:                        p = "\p" kStrStorageClass "Link Err"; break;
  128.         case    kUSBCRCErr:                            p = "\p" kStrStorageClass "Comms/Device err, bad CRC";  break;        
  129.         case    kUSBBitstufErr:                    p = "\p" kStrStorageClass "Comms/Device err, bitstuffing"; break;        
  130.         case    kUSBDataToggleErr:                p = "\p" kStrStorageClass "Comms/Device err, Bad data toggle"; break;        
  131.         case    kUSBEndpointStallErr:            p = "\p" kStrStorageClass "Device didn't understand"; break;        
  132.         case    kUSBNotRespondingErr:            p = "\p" kStrStorageClass "No device, device hung"; break;        
  133.         case    kUSBPIDCheckErr:                    p = "\p" kStrStorageClass "Comms/Device err, PID CRC error"; break;        
  134.         case    kUSBWrongPIDErr:                    p = "\p" kStrStorageClass "Comms/Device err, Bad or wrong PID"; break;        
  135.         case    kUSBOverRunErr:                    p = "\p" kStrStorageClass "Packet too large or more data than buffer"; break;        
  136.         case    kUSBUnderRunErr:                    p = "\p" kStrStorageClass "Less data than buffer"; break;        
  137.         case    kUSBRes1Err:                        p = "\p" kStrStorageClass "kUSBRes1Err"; break;        
  138.         case    kUSBRes2Err:                        p = "\p" kStrStorageClass "kUSBRes1Err"; break;        
  139.         case    kUSBBufOvrRunErr:                    p = "\p" kStrStorageClass "Buffer over run error"; break;        
  140.         case    kUSBBufUnderRunErr:                p = "\p" kStrStorageClass "Buffer under run error"; break;        
  141.         case    kUSBNotSent1Err:                    p = "\p" kStrStorageClass "Transaction not sent1"; break;        
  142.         case    kUSBNotSent2Err:                    p = "\p" kStrStorageClass "Transaction not sent2"; break;    
  143.         default:
  144.             p = "\p" kStrStorageClass "Unknown error nnnnnnnn";
  145.             HexStr( usbStatus, p + *p - 8 + 1 );
  146.             break;
  147.     }
  148.     
  149.     return kind == kPString? p: p + 1;
  150. }
  151.  
  152.  
  153. static unsigned char*
  154. StateStr(    OSStatus    refCon,
  155.                 int        kind )
  156. {
  157.     unsigned char *p;
  158.  
  159.     refCon &= ~(kCompletionPending | kRetryTransaction | kAsyncTransaction | kReturnFromDriver);
  160.     switch ( refCon )
  161.     {        
  162.         case kSetConfig:                                    p = kStrStorageClass "kSetConfig"; break;
  163.         case kGetFullConfiguration:                    p = kStrStorageClass "kGetFullConfiguration"; break;
  164.         case kFindStorageInterface:                    p = kStrStorageClass "kFindStorageInterface"; break;
  165.         case kStorageConfigureInterface:                p = kStrStorageClass "kStorageConfigureInterface"; break;
  166.         
  167.         case kNewInterfaceRef:                            p = kStrStorageClass "kNewInterfaceRef"; break;
  168.         case kStorageFindInterruptPipe:                p = kStrStorageClass "kStorageFindInterruptPipe"; break;
  169.         case kStorageFindBulkInPipe:                    p = kStrStorageClass "kStorageFindBulkInPipe"; break;
  170.         case kStorageFindBulkOutPipe:                    p = kStrStorageClass "kStorageFindBulkOutPipe"; break;
  171.                 
  172.         case kStorageReadInterrupt:                    p = kStrStorageClass "kStorageReadInterrupt"; break;
  173.         
  174.         case kStorageExecuteCommand:                    p = kStrStorageClass "kStorageExecuteCommand"; break;
  175.         case kStorageExecuteCommandCompletion:        p = kStrStorageClass "kStorageExecuteCommandCompletion"; break;
  176.         case kStorageBulkIOComplete:                    p = kStrStorageClass "kStorageBulkIOComplete"; break;
  177.         case kStorageGetStatus:                            p = kStrStorageClass "kStorageGetStatus"; break;
  178.         case kStorageGetStatusBulkRead:                p = kStrStorageClass "kStorageGetStatusBulkRead"; break;
  179.         
  180.         default:
  181.             p = "\pUnknown state nnnnnnnn";
  182.             HexStr( refCon, p + *p - 8 + 1 );
  183.             break;
  184.     }
  185.     return kind == kPString? p: p + 1;    
  186. }
  187. #endif
  188.  
  189. static unsigned char
  190. HiHex( int v )
  191. {
  192.     unsigned char    hinibble = (v >> 4) & 0x0f;
  193.     return hinibble + ((hinibble > 9)? ('A'-10): '0');
  194. }
  195.  
  196.  
  197. static unsigned char
  198. LoHex( int v )
  199. {
  200.     unsigned char    lonibble = v & 0x0f;
  201.     return lonibble + ((lonibble > 9)? ('A'-10): '0');
  202. }
  203.  
  204.  
  205. static void
  206. InitParamBlock(USBDeviceRef theDeviceRef, USBPB * paramblock)
  207. {
  208.     paramblock->usbReference =    theDeviceRef;
  209.     paramblock->pbVersion =        kUSBCurrentPBVersion;
  210.     paramblock->pbLength =        sizeof(USBPB);
  211.     paramblock->usb.cntl.WIndex =        0;             
  212.     paramblock->usbBuffer =        nil;        
  213.     paramblock->usbStatus =        noErr;
  214.     paramblock->usbReqCount =    0;
  215.     paramblock->usb.cntl.WValue =        0;
  216.     paramblock->usbFlags =        0;
  217. }
  218.  
  219.  
  220. static Boolean
  221. ImmediateError(OSStatus err)
  222. {
  223.     return((err != kUSBPending) && (err != noErr) );
  224. }
  225.  
  226.  
  227. OSStatus
  228. GetUSBVersion(UInt32* usbVersion)
  229. {
  230. OSStatus result;
  231.  
  232.     result = Gestalt('usbv', usbVersion);
  233.     
  234.     return result;
  235. }
  236.  
  237.  
  238. OSErr
  239. GetInterfaceDescriptor(    LogicalAddress pConfigDesc,
  240.                                 UInt32 ReqInterface,
  241.                                 USBInterfaceDescriptorPtr * hInterfaceDesc)
  242. {
  243. UInt32                            totalLength;
  244. void *                            pEndOfDescriptors;
  245. USBInterfaceDescriptorPtr    pMyIntDesc;
  246. USBDescriptorHeaderPtr        pCurrentDesc;
  247. UInt32                            anAddress,
  248.                                     anOffset;
  249.  
  250.     totalLength =            ((USBConfigurationDescriptorPtr)pConfigDesc)->totalLength;
  251.     pEndOfDescriptors =    (Ptr)pConfigDesc + totalLength;                // get the total length and add it to the start of the config space
  252.     pCurrentDesc =            (USBDescriptorHeaderPtr)pConfigDesc;        // point the currentdesc to the start of the config space
  253.     
  254.     while (pCurrentDesc < pEndOfDescriptors)                                // as long as we haven't exhausted all the descriptors
  255.     {
  256.         if (pCurrentDesc->descriptorType == kUSBInterfaceDesc)        // look at the current descriptor
  257.         {
  258.             pMyIntDesc = (USBInterfaceDescriptorPtr)pCurrentDesc;        // if it's an interface descriptor
  259.             if (pMyIntDesc->interfaceNumber == ReqInterface)            // see if it's the request descriptor
  260.             {
  261.                 *hInterfaceDesc = pMyIntDesc;                                    // if it is, then return with hInterfaceDesc set to the
  262.                 return kUSBNoErr;                                                    // current descriptor pointer
  263.             }
  264.         }
  265.         anAddress =        (unsigned long) pCurrentDesc;                        // Nope, that either wasn't an interface descriptor
  266.         anOffset  =        (unsigned long) pCurrentDesc->length;
  267.         anAddress +=    anOffset;
  268.         pCurrentDesc =    (USBDescriptorHeaderPtr) anAddress;
  269.     }                                                                                    // or it was, but not the droid we're looking for.
  270.     return -1;
  271. }
  272.  
  273. //****************************************************************************************************
  274. //
  275. //        StorageClassDriverAPI.c calls end up here...
  276. //
  277. //****************************************************************************************************
  278.  
  279. OSStatus
  280. StorageClassDriverInitialize(void)
  281. {
  282.     return noErr;
  283. }
  284.  
  285.  
  286. OSStatus
  287. StorageClassDriverControl(    UInt32    theControlSelector,
  288.                                     void        *theControlData)
  289. {
  290. #pragma unused (theControlData)
  291.  
  292. OSStatus        status;
  293.  
  294.     switch (theControlSelector)
  295.     {
  296.         case kControlDisableRemoval:
  297.             gOKToRemoval = false;
  298.             status = noErr;
  299.             IF_DEBUG( USBExpertStatus(gStorageClassInfo.deviceRef, "\pStorageClassDriver: kControlDisableRemoval", 0) );
  300.             break;
  301.             
  302.         case kControlEnableRemoval:
  303.             gOKToRemoval = true;
  304.             status = noErr;
  305.             IF_DEBUG( USBExpertStatus(gStorageClassInfo.deviceRef, "\pStorageClassDriver: kControlEnableRemoval", 0) );
  306.             break;
  307.         
  308.         default:
  309.             status = controlErr;
  310.             break;
  311.     }    
  312.     return status;
  313. }
  314.  
  315.  
  316. OSStatus
  317. StorageClassDriverStatus(    UInt32    theInfoSelector,
  318.                                     void        *theInfo)
  319. {
  320. OSStatus        status;
  321.  
  322.     switch (theInfoSelector)
  323.     {
  324.         case kStatusConfiguration:                        // Return the current confifuration status
  325.             *((UInt32*) theInfo) = gConfigureStatus;
  326.             status = noErr;
  327.             break;
  328.             
  329.         case kStatusDeviceStatus:
  330.             status = StorageClassDriverGetStatus( (StorageStatusPBPtr) theInfo );
  331.             break;
  332.         
  333.         case kStatusRemovalStatus:
  334.             *((Boolean*) theInfo) = gOKToRemoval;
  335.             status = noErr;
  336.             break;
  337.             
  338.         default:
  339.             status = statusErr;
  340.             break;
  341.     }    
  342.     return status;
  343. }
  344.  
  345.  
  346. // All device requests come through here
  347. OSStatus
  348. StorageClassDriverExecuteCommand( StorageExecuteCommandPBPtr cmdPBPtr )
  349. {
  350. OSStatus            myErr;
  351. //    IF_DEBUG( USBExpertStatus(gStorageClassInfo.deviceRef, "\pStorageClassDriverExecuteCommand", 0) );
  352.  
  353.     // Make sure we have been able to configure the device
  354.     if (gConfigured == false)
  355.     {
  356.         IF_DEBUG( USBExpertStatus(gStorageClassInfo.deviceRef, "\pStorageClassDriver StorageClassDriverExecuteCommand not configured", 0) );
  357.         return kClassNotConfiguredErr;
  358.     }
  359.         
  360.     // check if we already have a read in progress, if so return error.
  361.     if (gCommandPB.busy == true)
  362.     {
  363.         IF_DEBUG( USBExpertStatus(gStorageClassInfo.deviceRef, "\pStorageClassDriver StorageClassDriverExecuteCommand busy", 0) );
  364.         return kCommandBusyError;
  365.     }
  366.     
  367.     cmdPBPtr->status = kRequestPending;
  368.  
  369.     BlockZero(&gCommandPB, sizeof(StorageClassTransactionPB));
  370.         
  371.     gCommandPB.busy = true;
  372.  
  373.     InitParamBlock(gStorageClassInfo.interfaceRef, &gCommandPB.usbPB);
  374.     
  375.     // Get a local copy of the callers cdb
  376.     BlockCopy(&cmdPBPtr->cdb[0], &gCommandPB.cdb[0], kCDBSize);
  377.     
  378.     gCommandPB.flags = cmdPBPtr->flags;
  379.     
  380.     gCommandPB.userPBPtr = (StorageExecuteCommandPBPtr) cmdPBPtr;                // Save the ptr to the callers PB
  381.     
  382.     gCommandPB.usbPB.usb.cntl.BMRequestType =    USBMakeBMRequestType(kUSBOut, kUSBClass, kUSBInterface);            
  383.     
  384.     gCommandPB.usbPB.usb.cntl.BRequest =        0;
  385.     gCommandPB.usbPB.usb.cntl.WValue =            0;
  386.     gCommandPB.usbPB.usb.cntl.WIndex =            0;
  387.     
  388.     gCommandPB.usbPB.usbBuffer =            (Ptr)&gCommandPB.cdb[0];
  389.     gCommandPB.usbPB.usbReqCount =        kCDBSize;
  390.     gCommandPB.usbPB.usbFlags =            0;
  391.         
  392.     gCommandPB.usbPB.usbRefcon =            kStorageExecuteCommand;
  393.     
  394.     gCommandPB.usbPB.usbCompletion =        (USBCompletion)ExecuteCommandCompletion;                // Don't use double buffering for builk I/O
  395.         
  396.     myErr = USBDeviceRequest(&gCommandPB.usbPB);
  397.             
  398.     return myErr;
  399. }
  400.  
  401. static void ExecuteCommandCompletion(USBPB* usbPB)
  402. {
  403. OSStatus                            myErr;
  404. StorageExecuteCommandPBPtr    cmdPBPtr;
  405.  
  406.     // Retrieve the callers pb
  407.     cmdPBPtr = (StorageExecuteCommandPBPtr) gCommandPB.userPBPtr;
  408.         
  409. //    IF_DEBUG( USBExpertStatus(gStorageClassInfo.deviceRef, StateStr(usbPB->usbRefcon, kPString) , 5 ) );
  410.  
  411.     switch(usbPB->usbRefcon)
  412.     {
  413.         case kStorageExecuteCommand:        // Device request completion
  414.             // First check to see if an error occurred on the command out
  415.             if (usbPB->usbStatus != noErr)
  416.             {
  417.                 // Clear stalled control pipe
  418.                 IF_DEBUG( USBExpertStatus(gStorageClassInfo.deviceRef, "\pStorageClass: kStorageExecuteCommand error. usbStatus:" , usbPB->usbStatus ) );
  419.                 USBClearPipeStallByReference(usbPB->usbReference);
  420.                 cmdPBPtr->status = usbPB->usbStatus;
  421.                                 
  422.                 gCommandPB.busy = false;
  423.                 if(cmdPBPtr->completionProc != nil)
  424.                 {
  425.                     (*cmdPBPtr->completionProc)((StorageExecuteCommandPBPtr) cmdPBPtr);
  426.                 }
  427.                 break;
  428.             }
  429.             
  430.             // If there is to be no data transfer then we are done and can return to the caller
  431.             if (gCommandPB.flags & kStorageNoData)
  432.             {
  433.                 cmdPBPtr->status = usbPB->usbStatus;
  434.                                 
  435.                 gCommandPB.busy = false;
  436.                 (*cmdPBPtr->completionProc)((StorageExecuteCommandPBPtr) cmdPBPtr);
  437.                 
  438.                 break;
  439.             }
  440.             // Setup the usb pb for either bulk in or out
  441.             if (gCommandPB.flags & kStorageDataIn)
  442.                 InitParamBlock(gStorageClassInfo.readPipeRef, usbPB);
  443.             else if (gCommandPB.flags & kStorageDataOut)
  444.                 InitParamBlock(gStorageClassInfo.writePipeRef, usbPB);
  445.                             
  446.             // Make sure we clear out the actualCount before starting data transfers
  447.             cmdPBPtr->actualCount = 0;
  448.             
  449.             // Check to see if the amount of data to be transferred is greater
  450.             // than kUSBMaxBulkTransfer.  This is to get around an issue with
  451.             // the USB Manager/USL where the amount of data transferred per
  452.             // Bulk Request needs to be limited to a specific amount
  453.             if ( cmdPBPtr->expectedCount > kUSBMaxBulkTransfer )
  454.             {
  455.                 usbPB->usbReqCount     = kUSBMaxBulkTransfer;
  456.             }
  457.             else
  458.             {
  459.                 usbPB->usbReqCount     = cmdPBPtr->expectedCount;
  460.             }
  461.             
  462.             usbPB->usbRefcon =        kStorageBulkIOComplete;
  463.             usbPB->usbActCount =        0;
  464.             usbPB->usbBuffer =        cmdPBPtr->userBuffer;
  465.             usbPB->usbCompletion =    (USBCompletion)ExecuteCommandCompletion;
  466.             
  467.             // Start a bulk in or out transaction
  468.             if (gCommandPB.flags & kStorageDataIn)
  469.                 myErr = USBBulkRead(&gCommandPB.usbPB);
  470.             else if (gCommandPB.flags & kStorageDataOut)
  471.                 myErr = USBBulkWrite(&gCommandPB.usbPB);
  472.             
  473.             if    (ImmediateError(myErr))
  474.             {
  475.                 IF_DEBUG( USBExpertFatalError(gStorageClassInfo.deviceRef, kUSBInternalErr, "\pStorageClass: kStorageExecuteCommand - immediate error", myErr) );
  476.                 cmdPBPtr->actualCount =    usbPB->usbActCount;
  477.                 cmdPBPtr->status = myErr;
  478.                 gCommandPB.busy = false;
  479.                 (*cmdPBPtr->completionProc)((StorageExecuteCommandPBPtr) cmdPBPtr);
  480.             }
  481.             break;
  482.         
  483.         case kStorageBulkIOComplete:
  484.         
  485.             cmdPBPtr->actualCount +=    usbPB->usbActCount;                // Update the users byte count
  486.             cmdPBPtr->status =        usbPB->usbStatus;                    // and status
  487.             
  488.             if (usbPB->usbStatus != noErr)                                // Clear a possible pipe stall
  489.             {
  490.                 IF_DEBUG( USBExpertStatus(gStorageClassInfo.deviceRef, "\pStorageClass: kStorageBulkIOComplete error. usbStatus:" , usbPB->usbStatus ) );
  491.                 USBClearPipeStallByReference(usbPB->usbReference);
  492.             }
  493.             else if ( cmdPBPtr->actualCount != cmdPBPtr->expectedCount)
  494.             {
  495.                 // If we have not yet transfered all the data and there are no Errors
  496.                 // Setup the usb pb for either bulk in or out
  497.                 if (gCommandPB.flags & kStorageDataIn)
  498.                 {
  499.                     InitParamBlock(gStorageClassInfo.readPipeRef, usbPB);
  500.                 }
  501.                 else if (gCommandPB.flags & kStorageDataOut)
  502.                 {
  503.                     InitParamBlock(gStorageClassInfo.writePipeRef, usbPB);
  504.                 }
  505.     
  506.                 if ( (cmdPBPtr->expectedCount - cmdPBPtr->actualCount) > kUSBMaxBulkTransfer )
  507.                 {
  508.                     usbPB->usbReqCount     = kUSBMaxBulkTransfer;
  509.                 }
  510.                 else
  511.                 {
  512.                     usbPB->usbReqCount     = (cmdPBPtr->expectedCount - cmdPBPtr->actualCount);
  513.                 }
  514.                 
  515.                 usbPB->usbRefcon         = kStorageBulkIOComplete;
  516.                 usbPB->usbActCount     = 0;
  517.                 usbPB->usbBuffer         = (cmdPBPtr->userBuffer) + (cmdPBPtr->actualCount);
  518.                 usbPB->usbCompletion = (USBCompletion)ExecuteCommandCompletion;
  519.                 
  520.                 // Continue a bulk in or out transaction
  521.                 if (gCommandPB.flags & kStorageDataIn)
  522.                 {
  523.                     myErr = USBBulkRead(&gCommandPB.usbPB);
  524.                 }
  525.                 else if (gCommandPB.flags & kStorageDataOut)
  526.                 {
  527.                     myErr = USBBulkWrite(&gCommandPB.usbPB);
  528.                 }
  529.                 
  530.                 if    (ImmediateError(myErr))
  531.                 {
  532.                     USBExpertFatalError(gStorageClassInfo.deviceRef, kUSBInternalErr, "\pStorageClass: kStorageExecuteCommand - immediate error", myErr);
  533.                     cmdPBPtr->status = myErr;
  534.                     gCommandPB.busy = false;
  535.                     if(cmdPBPtr->completionProc != nil)
  536.                     {
  537.                         (*cmdPBPtr->completionProc)((StorageExecuteCommandPBPtr) cmdPBPtr);
  538.                     }
  539.                 }
  540.                 break;
  541.             }
  542.             
  543.             gCommandPB.busy = false;
  544.             (*cmdPBPtr->completionProc)((StorageExecuteCommandPBPtr) cmdPBPtr);
  545.             break;
  546.             
  547.         default:
  548.             IF_DEBUG( USBExpertFatalError(gStorageClassInfo.deviceRef, kUSBInternalErr, "\pStorageClass: ExecuteCommandCompletion - unknown state!", 5) );
  549.             cmdPBPtr->actualCount =    0;
  550.             cmdPBPtr->status = kUSBInternalErr;
  551.                         
  552.             gCommandPB.busy = false;
  553.             (*cmdPBPtr->completionProc)((StorageExecuteCommandPBPtr) cmdPBPtr);
  554.             break;
  555.     }
  556. }
  557.  
  558. OSStatus
  559. StorageClassDriverGetStatus( StorageStatusPBPtr statusPBPtr )
  560. {
  561. OSStatus    myErr;
  562.     
  563.     IF_DEBUG( USBExpertStatus(gStorageClassInfo.deviceRef, "\p • StorageClassDriverGetStatus", 0) );
  564.  
  565.     // Make sure we have been able to configure the device
  566.     if (gConfigured == false)
  567.     {
  568.         IF_DEBUG( USBExpertStatus(gStorageClassInfo.deviceRef, "\pStorageClassDriver StorageClassDriverExecuteCommand not configured", 0) );
  569.         return kClassNotConfiguredErr;
  570.     }
  571.         
  572.     // check if we already have a status request in progress, if so return error.
  573.     if (gGetStatusPB.busy == true)
  574.     {
  575.         IF_DEBUG( USBExpertStatus(gStorageClassInfo.deviceRef, "\pStorageClassDriver StorageClassDriverGetStatus busy", 0) );
  576.         return kCommandBusyError;
  577.     }
  578.     
  579.     BlockZero(&gGetStatusPB, sizeof(StorageClassStatusPB));
  580.     
  581.     gGetStatusPB.busy = true;
  582.     
  583.     gGetStatusPB.userPBPtr = statusPBPtr;
  584.     
  585.     InitParamBlock(gStorageClassInfo.interfaceRef, &gGetStatusPB.usbPB);
  586.             
  587.     gGetStatusPB.usbPB.usb.cntl.BMRequestType =    USBMakeBMRequestType(kUSBIn, kUSBStandard, kUSBDevice);            
  588.     
  589.     gGetStatusPB.usbPB.usb.cntl.BRequest =            kUSBRqGetStatus;
  590.     gGetStatusPB.usbPB.usb.cntl.WIndex =            0;
  591.     gGetStatusPB.usbPB.usb.cntl.WValue =            0;
  592.     
  593.     gGetStatusPB.usbPB.usbBuffer =            (Ptr)&gGetStatusPB.status[0];
  594.     gGetStatusPB.usbPB.usbReqCount =            kStatusSize;
  595.     gGetStatusPB.usbPB.usbFlags =                0;
  596.         
  597.     gGetStatusPB.usbPB.usbRefcon =            kStorageGetStatus;
  598.     gGetStatusPB.usbPB.usbCompletion =        (USBCompletion)GetStatusCompletion;
  599.             
  600.     myErr = USBDeviceRequest(&gGetStatusPB.usbPB);
  601.             
  602.     return myErr;
  603. }
  604.  
  605.  
  606.  
  607. static void GetStatusCompletion(USBPB* usbPB)
  608. {
  609. StorageStatusPBPtr    userPBPtr;
  610.     
  611.     IF_DEBUG( USBExpertStatus(gStorageClassInfo.deviceRef, StateStr(usbPB->usbRefcon, kPString) , 6 ) );
  612.     
  613.     // Retrieve the callers pb
  614.     userPBPtr = (StorageStatusPBPtr) gGetStatusPB.userPBPtr;
  615.         
  616.     userPBPtr->status =                usbPB->usbStatus;
  617.     userPBPtr->deviceStatus[0] =    gGetStatusPB.status[0];
  618.     userPBPtr->deviceStatus[1] =    gGetStatusPB.status[1];
  619.                     
  620.     gGetStatusPB.busy = false;
  621.     (*userPBPtr->completionProc)((StorageExecuteCommandPBPtr) userPBPtr);
  622. }
  623.  
  624.  
  625. OSStatus
  626. StorageClassDriverAbortTransaction( StorageControlPBPtr controlPBPtr )
  627. {
  628. OSStatus            myErr;
  629.  
  630.     IF_DEBUG( USBExpertStatus(gStorageClassInfo.deviceRef, "\p • StorageClassDriverAbortTransaction", 0) );
  631.  
  632.     // Make sure we have been able to configure the device
  633.     if (gConfigured == false)
  634.     {
  635.         IF_DEBUG( USBExpertStatus(gStorageClassInfo.deviceRef, "\pStorageClassDriver StorageClassDriverAbortTransaction not configured", 0) );
  636.         return kClassNotConfiguredErr;
  637.     }
  638.         
  639.     // check if we already have a status request in progress, if so return error.
  640.     if (gControlPB.busy == true)
  641.     {
  642.         IF_DEBUG( USBExpertStatus(gStorageClassInfo.deviceRef, "\pStorageClassDriver StorageClassDriverAbortTransaction busy", 0) );
  643.         return kCommandBusyError;
  644.     }
  645.     
  646.     BlockZero(&gControlPB, sizeof(StorageControlPB));
  647.     
  648.     gControlPB.busy = true;
  649.     
  650.     gControlPB.userPBPtr = controlPBPtr;
  651.     
  652.     InitParamBlock(gStorageClassInfo.interfaceRef, &gControlPB.usbPB);
  653.             
  654.     gControlPB.usbPB.usb.cntl.BMRequestType =    0x02;            // Clear feature        
  655.     
  656.     gControlPB.usbPB.usb.cntl.BRequest =        kUSBRqClearFeature;
  657.     
  658.     if (controlPBPtr->selector == 0)                        // Abort read pipe
  659.         gControlPB.usbPB.usb.cntl.WIndex =        0x82;
  660.     else                                                            // Abort write pipe
  661.         gControlPB.usbPB.usb.cntl.WIndex =        0x01;
  662.         
  663.     gControlPB.usbPB.usb.cntl.WValue =            0;                // 0 = clear endpoint stall
  664.     
  665.     gControlPB.usbPB.usbBuffer =            nil;
  666.     gControlPB.usbPB.usbReqCount =        0;
  667.     gControlPB.usbPB.usbFlags =            0;
  668.         
  669.     gControlPB.usbPB.usbRefcon =            kStorageGetStatus;
  670.     gControlPB.usbPB.usbCompletion =        (USBCompletion)AbortTransactionCompletion;
  671.             
  672.     myErr = USBDeviceRequest(&gControlPB.usbPB);
  673.             
  674.     return myErr;
  675. }
  676.  
  677.  
  678.  
  679. static void AbortTransactionCompletion(USBPB* usbPB)
  680. {
  681. StorageControlPBPtr    userPBPtr;
  682.     
  683.     IF_DEBUG( USBExpertStatus(gStorageClassInfo.deviceRef, StateStr(usbPB->usbRefcon, kPString) , 7 ) );
  684.     
  685.     // Retrieve the callers pb
  686.     userPBPtr = (StorageControlPBPtr) gControlPB.userPBPtr;
  687.         
  688.     userPBPtr->status =                usbPB->usbStatus;
  689.                     
  690.     gControlPB.busy = false;
  691.     (*userPBPtr->completionProc)((StorageExecuteCommandPBPtr) userPBPtr);
  692. }
  693.  
  694.  
  695. static void ReadInterruptCompletion(USBPB* usbPB)
  696. {
  697.     gStorageClassInfo.transDepth--;
  698.     
  699.     if (usbPB->usbStatus == kUSBEndpointStallErr)
  700.     {
  701.         USBClearPipeStallByReference(gStorageClassInfo.interruptPipeRef);
  702.     }
  703.     InitParamBlock(gStorageClassInfo.interruptPipeRef, usbPB);
  704.  
  705.     usbPB->usbBuffer =        (Ptr)gStorageClassInfo.interruptReport;
  706.     usbPB->usbReqCount =        0x02;
  707.     usbPB->usbRefcon =        kStorageReadInterrupt;
  708.     usbPB->usbCompletion =    (USBCompletion)ReadInterruptCompletion;
  709.     
  710.     StorageDeviceInitiateConfiguration(usbPB);
  711. }
  712.  
  713. void
  714. StorageDeviceInitiateConfiguration(USBPB *usbPB)
  715. {
  716. OSStatus myErr;
  717. StorageClassTransactionPB*    pTransPB = (StorageClassTransactionPB*) usbPB;
  718.  
  719.     gStorageClassInfo.transDepth++;
  720.     
  721.     if ((gStorageClassInfo.transDepth < 0) || (gStorageClassInfo.transDepth > kMaxTransitions))
  722.     {
  723.         IF_DEBUG( USBExpertFatalError(usbPB->usbReference, kUSBInternalErr, "\pStorageClass: Illegal Transaction Depth", usbPB->usbRefcon) );
  724.         gConfigureStatus = kConfigureFailed;
  725.     }
  726.     IF_DEBUG( USBExpertStatus(gStorageClassInfo.deviceRef, StateStr(usbPB->usbRefcon, kPString) , 2 ) );
  727.     
  728.     switch(usbPB->usbRefcon & ~kRetryTransaction)
  729.     {    
  730.         case kGetFullConfiguration:
  731.             InitParamBlock(gStorageClassInfo.deviceRef, usbPB);
  732.             
  733.             usbPB->usb.cntl.WIndex =            0;             // First try configuration 0, if it doesn't succeed, then try config 1
  734.             usbPB->usbRefcon |=        kCompletionPending;
  735.             usbPB->usbCompletion =    (USBCompletion)StorageDeviceConfigureCompletion;
  736.             
  737.             myErr = USBGetFullConfigurationDescriptor(usbPB);
  738.             if(ImmediateError(myErr))
  739.             {
  740.                 gConfigureStatus = kConfigureFailed;
  741.                 IF_DEBUG( USBExpertFatalError(usbPB->usbReference, kUSBInternalErr, "\pStorageClass: USBGetFullConfiguration (#0) - immediate error", myErr) );
  742.             }
  743.             break;
  744.         
  745.         case kSetConfig:
  746.             InitParamBlock(gStorageClassInfo.deviceRef, usbPB);
  747.             
  748.             usbPB->usb.cntl.BMRequestType =    USBMakeBMRequestType(kUSBOut, kUSBStandard, kUSBDevice);
  749.             usbPB->usb.cntl.BRequest =            kUSBRqSetConfig;
  750.             usbPB->usb.cntl.WValue =            gStorageClassInfo.pFullConfigDescriptor->configValue;         // Use configuration ID value from descriptor
  751.             usbPB->usbRefcon |=             kCompletionPending;
  752.             
  753.             usbPB->usbCompletion =        (USBCompletion)StorageDeviceConfigureCompletion;
  754.             
  755.             myErr = USBDeviceRequest(usbPB);
  756.             if(ImmediateError(myErr))
  757.             {
  758.                 gConfigureStatus = kConfigureFailed;
  759.                 IF_DEBUG( USBExpertFatalError(usbPB->usbReference, kUSBInternalErr, "\pStorageClass: kSetConfig - immediate error", myErr) );
  760.             }
  761.             break;
  762.         
  763.         case kFindStorageInterface:
  764.             InitParamBlock(gStorageClassInfo.deviceRef, usbPB);
  765.             usbPB->usbActCount =        0;
  766.  
  767.             usbPB->usbClassType =    kDriverClassID;
  768.             usbPB->usbSubclass =        kDriverSubClassID;
  769.             usbPB->usbProtocol =        0;
  770.             usbPB->usb.cntl.WValue =        0;
  771.             usbPB->usbRefcon |=        kCompletionPending;
  772.             usbPB->usbCompletion =    (USBCompletion)StorageDeviceConfigureCompletion;
  773.             
  774.             myErr = USBFindNextInterface(usbPB);
  775.             if(ImmediateError(myErr))
  776.             {
  777.                 gConfigureStatus = kConfigureFailed;
  778.                 IF_DEBUG( USBExpertFatalError(usbPB->usbReference, kUSBInternalErr, "\pStorageClass: kFindStorageInterface - immediate error", myErr) );
  779.             }
  780.             break;
  781.             
  782.         case kNewInterfaceRef:
  783.             InitParamBlock(gStorageClassInfo.deviceRef, usbPB);
  784.             // Note: gStorageClassInfo.usbWIndex will be set to zero by InitParamBlock
  785.             // so set it again to gStorageClassInfo.interfaceIndex before calling USBNewInterfaceRef
  786.             usbPB->usbActCount =        0;
  787.             usbPB->usb.cntl.WIndex =            gStorageClassInfo.interfaceNumber;
  788.             usbPB->usbRefcon |=        kCompletionPending;
  789.             usbPB->usbCompletion =    (USBCompletion)StorageDeviceConfigureCompletion;
  790.  
  791.             myErr = USBNewInterfaceRef(usbPB);
  792.             if(ImmediateError(myErr))
  793.             {
  794.                 gConfigureStatus = kConfigureFailed;
  795.                 IF_DEBUG( USBExpertFatalError(usbPB->usbReference, kUSBInternalErr, "\pStorageClass: kNewInterfaceRef - immediate error", myErr) );
  796.             }
  797.             break;
  798.                 
  799.         case kStorageConfigureInterface:
  800.             InitParamBlock(gStorageClassInfo.interfaceRef, usbPB);
  801.  
  802.             usbPB->usbActCount =        0;
  803.             usbPB->usbCompletion =    (USBCompletion)StorageDeviceConfigureCompletion;
  804.             usbPB->usbRefcon |=        kCompletionPending;
  805.             
  806.             gStorageClassInfo.interfaceNumber =        0;            // Find First calls 'FindNextInterface' with WIndex = 0
  807.                                                                             // Find Next calls 'FindNextInterface' with WIndex = InterfaceNumber
  808.             
  809.             myErr = USBConfigureInterface(usbPB);
  810.             if (ImmediateError(myErr))
  811.             {
  812.                 gConfigureStatus = kConfigureFailed;
  813.                 IF_DEBUG( USBExpertFatalError(gStorageClassInfo.deviceRef, kUSBInternalErr, "\pStorageClass: kStorageConfigureInterface - immediate error", myErr) );
  814.             }
  815.             break;
  816.         
  817.         case kStorageFindInterruptPipe:
  818.             InitParamBlock(gStorageClassInfo.interfaceRef, usbPB);
  819.  
  820.             usbPB->usbFlags =            kUSBIn;
  821.             usbPB->usbClassType =    kUSBInterrupt;
  822.             usbPB->usbCompletion =    (USBCompletion)StorageDeviceConfigureCompletion;
  823.             usbPB->usbRefcon |=        kCompletionPending;
  824.  
  825.             myErr = USBFindNextPipe( usbPB );
  826.             if (ImmediateError(myErr))
  827.             {
  828.                 gConfigureStatus = kConfigureFailed;
  829.                 IF_DEBUG( USBExpertFatalError(gStorageClassInfo.deviceRef, kUSBInternalErr, "\pStorageClass: kStorageFindInterruptPipe - immediate error", myErr) );
  830.                 usbPB->usbRefcon = kReturnFromDriver;
  831.             }
  832.             break;
  833.         
  834.         case kStorageFindBulkInPipe:
  835.             InitParamBlock(gStorageClassInfo.interfaceRef, usbPB);
  836.  
  837.             usbPB->usbFlags =            kUSBIn;
  838.             usbPB->usbClassType =    kUSBBulk;
  839.             usbPB->usbCompletion =    (USBCompletion)StorageDeviceConfigureCompletion;
  840.             usbPB->usbRefcon |=        kCompletionPending;
  841.  
  842.             myErr = USBFindNextPipe( usbPB );
  843.             if (ImmediateError(myErr))
  844.             {
  845.                 gConfigureStatus = kConfigureFailed;
  846.                 IF_DEBUG( USBExpertFatalError(gStorageClassInfo.deviceRef, kUSBInternalErr, "\pStorageClass: kStorageFindBulkInPipe - immediate error", myErr) );
  847.                 usbPB->usbRefcon = kReturnFromDriver;
  848.             }
  849.             break;
  850.         
  851.         case kStorageFindBulkOutPipe:
  852.             InitParamBlock(gStorageClassInfo.interfaceRef, usbPB);
  853.  
  854.             usbPB->usbFlags =            kUSBOut;
  855.             usbPB->usbClassType =    kUSBBulk;
  856.             usbPB->usbCompletion =    (USBCompletion)StorageDeviceConfigureCompletion;
  857.             usbPB->usbRefcon |=        kCompletionPending;
  858.  
  859.             myErr = USBFindNextPipe( usbPB );
  860.             if (ImmediateError(myErr))
  861.             {
  862.                 gConfigureStatus = kConfigureFailed;
  863.                 IF_DEBUG( USBExpertFatalError(gStorageClassInfo.deviceRef, kUSBInternalErr, "\pStorageClass: kStorageFindBulkOutPipe - immediate error", myErr) );
  864.                 usbPB->usbRefcon =    kReturnFromDriver;
  865.             }
  866.             break;
  867.         
  868.         case kStorageReadInterrupt:            
  869.             InitParamBlock(gStorageClassInfo.interruptPipeRef, usbPB);
  870.  
  871.             usbPB->usbBuffer =        (Ptr)gStorageClassInfo.interruptReport;
  872.             usbPB->usbReqCount =        0x02;
  873.             usbPB->usbCompletion =    (USBCompletion)ReadInterruptCompletion;
  874.             usbPB->usbRefcon |=        kCompletionPending;
  875.         
  876.             myErr = USBIntRead(usbPB);
  877.             if(ImmediateError(myErr))
  878.             {
  879.                 gConfigureStatus = kConfigureFailed;
  880.                 IF_DEBUG( USBExpertFatalError(gStorageClassInfo.deviceRef, kUSBInternalErr, "\pStorageClass: kStorageReadInterrupt - immediate error", myErr) );
  881.             }
  882.             break;
  883.             
  884.         case kReturnFromDriver:
  885.             break;
  886.             
  887.         default:
  888.             gConfigureStatus = kConfigureFailed;
  889.             IF_DEBUG( USBExpertFatalError(usbPB->usbReference, kUSBInternalErr, "\pStorageClass - Transaction initiated with bad refcon value", usbPB->usbRefcon) );
  890.             usbPB->usbRefcon = kUndefined + kReturnFromDriver;
  891.             break;
  892.     }
  893.     
  894. // At this point the control is returned to the system.  If a USB transaction
  895. // has been initiated, then it will call the Complete procs
  896. // (below) to handle the results of the transaction.
  897. }
  898.  
  899. static void
  900. StorageDeviceConfigureCompletion(USBPB *usbPB)
  901. {
  902. StorageClassTransactionPB*        pTransPB = (StorageClassTransactionPB*) usbPB;
  903. USBInterfaceDescriptorPtr        pInterfaceDescriptor;
  904. UInt32                                i;
  905.  
  906.     gStorageClassInfo.transDepth--;
  907.         
  908.     IF_DEBUG( USBExpertStatus(gStorageClassInfo.deviceRef, StateStr(usbPB->usbRefcon, kPString) , 3 ) );
  909.     
  910.     if ((gStorageClassInfo.transDepth < 0) || (gStorageClassInfo.transDepth > 1))
  911.     {
  912.         gConfigureStatus = kConfigureFailed;
  913.         IF_DEBUG( USBExpertFatalError(usbPB->usbReference, kUSBInternalErr, "\pStorageClass - Illegal Transaction Depth", gStorageClassInfo.transDepth) );
  914.     }
  915.     
  916.     // We should only retry if the error is a USB transaction problem
  917.     // Device errors are handled outside of the state machine.
  918.     if ((usbPB->usbStatus != noErr) && (usbPB->usbStatus != kUSBPending))
  919.     {
  920.         IF_DEBUG( USBExpertStatus(usbPB->usbReference, "\pStorage Driver: Completion Error", usbPB->usbStatus) );
  921.         usbPB->usbRefcon &= ~(kCompletionPending + kReturnFromDriver);
  922.         usbPB->usbRefcon |= kRetryTransaction;
  923.         gStorageClassInfo.retryCount--;
  924.         if (!gStorageClassInfo.retryCount)
  925.         {
  926.             gConfigureStatus = kConfigureFailed;
  927.             IF_DEBUG( USBExpertFatalError(usbPB->usbReference, kUSBInternalErr, "\pStorageClass: Too many retries", usbPB->usbRefcon) );
  928.             usbPB->usbRefcon = kReturnFromDriver;
  929.             return;
  930.         }
  931.     }
  932.     else
  933.     {
  934.         usbPB->usbRefcon &= ~kRetryTransaction;
  935.         gStorageClassInfo.retryCount = kStorageRetryCount;
  936.     }
  937.  
  938.     if (usbPB->usbRefcon & kCompletionPending)             
  939.     {                                                
  940.         usbPB->usbRefcon &= ~(kCompletionPending + kReturnFromDriver);
  941.         switch(usbPB->usbRefcon)
  942.         {
  943.             case kGetFullConfiguration:
  944.                 usbPB->usbRefcon = kSetConfig;
  945.                 gStorageClassInfo.pFullConfigDescriptor = usbPB->usbBuffer;        // Save the config descriptor
  946.                 if (gStorageClassInfo.pFullConfigDescriptor == nil)
  947.                 {
  948.                     gConfigureStatus = kConfigureFailed;
  949.                     usbPB->usbRefcon = kReturnFromDriver;
  950.                     
  951.                     IF_DEBUG( USBExpertFatalError(usbPB->usbReference, kUSBInternalErr, "\pStorageClass: USBGetFullConfiguration - pointer is nil", usbPB->usbRefcon) );
  952.                 }
  953.                 break;
  954.                 
  955.             case kSetConfig:
  956.                 BlockCopy(    (void *) &gStorageClassInfo.pFullConfigDescriptor,
  957.                                 (void *) &gStorageClassInfo.partialConfigDescriptor,
  958.                                 (Size) (sizeof(USBConfigurationDescriptor) ) );
  959.                 
  960.                 for (i=0; i < gStorageClassInfo.partialConfigDescriptor.numInterfaces; i++)
  961.                 {
  962.                     gStorageClassInfo.interfaceRefArray[i] = 0;
  963.                     
  964.                     GetInterfaceDescriptor(    gStorageClassInfo.pFullConfigDescriptor,
  965.                                                     i,
  966.                                                     &pInterfaceDescriptor);
  967.                     BlockCopy(    (void *)pInterfaceDescriptor,
  968.                                     (void *)(&(gStorageClassInfo.interfaceDescriptors[i])),
  969.                                     (Size)(pInterfaceDescriptor->length));
  970.                 }
  971.                 
  972.                 gStorageClassInfo.pInterfaceDescriptor = &(gStorageClassInfo.interfaceDescriptors[0]);
  973.                 
  974.                 gStorageClassInfo.interfaceIndex =        0;
  975.                 gStorageClassInfo.interfaceCount =        gStorageClassInfo.partialConfigDescriptor.numInterfaces;
  976.                 usbPB->usbRefcon =                            kFindStorageInterface;
  977.                 break;
  978.                 
  979.             case kFindStorageInterface:
  980.                 gStorageClassInfo.interfaceNumber =        usbPB->usb.cntl.WIndex;
  981.                 usbPB->usbRefcon =                            kNewInterfaceRef;
  982.                 break;
  983.                 
  984.             case kNewInterfaceRef:
  985.                 gStorageClassInfo.interfaceRef =        usbPB->usbReference;
  986.                 usbPB->usbRefcon =                        kStorageConfigureInterface;
  987.                 break;
  988.                 
  989.             case kStorageConfigureInterface:
  990.                 usbPB->usbRefcon = kStorageFindInterruptPipe;
  991.                 break;
  992.             
  993.             case kStorageFindInterruptPipe:                                
  994.                 gStorageClassInfo.interruptPipeRef =     usbPB->usbReference;
  995.                 usbPB->usbRefcon =                            kStorageFindBulkInPipe;
  996.                 break;
  997.                 
  998.             case kStorageFindBulkInPipe:
  999.                 gStorageClassInfo.readPipeRef =     usbPB->usbReference;
  1000.                 usbPB->usbRefcon =                    kStorageFindBulkOutPipe;
  1001.                 break;
  1002.             
  1003.             case kStorageFindBulkOutPipe:
  1004.                 gStorageClassInfo.writePipeRef = usbPB->usbReference;
  1005.                 gConfigured = true;                                // Set the configured flag so we can respond to calls via the dispatch table
  1006.                 gConfigureStatus = kConfigureComplete;        // Flag for client to determine that we are no configured
  1007.                 IF_DEBUG(USBExpertStatus(gStorageClassInfo.deviceRef, "\pStorageClass: Driver Configured.", 3 ) );            
  1008.                 usbPB->usbRefcon = kReturnFromDriver;
  1009.                 break;
  1010.             
  1011.             case kStorageReadInterrupt:    
  1012.     //            ProcessStorageInterrupt(pStoragePB);
  1013.                 IF_DEBUG( USBExpertStatus(gStorageClassInfo.deviceRef, "\pStorageClass: kStorageReadInterrupt. Byte 0:", gStorageClassInfo.interruptReport[0] ));
  1014.                 IF_DEBUG( USBExpertStatus(gStorageClassInfo.deviceRef, "\pStorageClass: kStorageReadInterrupt. Byte 1:", gStorageClassInfo.interruptReport[1] ));
  1015.                 
  1016.                 usbPB->usbRefcon = kStorageReadInterrupt;
  1017.                 break;
  1018.     
  1019.             case kNilCompletion:
  1020.             default:
  1021.                 if ( usbPB->usbStatus == noErr )
  1022.                     usbPB->usbRefcon = kUndefined | kReturnFromDriver;
  1023.                 break;
  1024.         }
  1025.     }
  1026.     
  1027.     if ( usbPB->usbStatus == noErr )
  1028.     {
  1029.         if (!(usbPB->usbRefcon & kReturnFromDriver))
  1030.             StorageDeviceInitiateConfiguration(usbPB);
  1031.     }
  1032.     else
  1033.     {
  1034.         gConfigureStatus = kConfigureFailed;
  1035.         IF_DEBUG( USBExpertFatalError(gStorageClassInfo.deviceRef, usbPB->usbStatus, StateStr(usbPB->usbRefcon, kPString), usbPB->usbRefcon) );
  1036.         IF_DEBUG( USBExpertFatalError(gStorageClassInfo.deviceRef, usbPB->usbStatus, USBStatusStr(usbPB->usbStatus, kPString), 0) );
  1037.     }
  1038. }
  1039.  
  1040.  
  1041. void 
  1042. StorageDriverEntry(    USBDeviceRef                    deviceRef,
  1043.                             USBDeviceDescriptorPtr        deviceDescriptorPtr,
  1044.                             USBInterfaceDescriptorPtr    pInterfaceDescriptor)
  1045. {
  1046.     UInt32    usbVersion;
  1047.             
  1048.     IF_DEBUG( USBExpertStatus(deviceRef, "\pStorage Driver Entry" , 1 ) );
  1049.     
  1050.     if( !gBeenThereDoneThat)
  1051.     {
  1052.         gBeenThereDoneThat = true;
  1053.         
  1054.         // Check for the correct version of the USB manager.
  1055.         // We are ok with all version later than 1.0
  1056.         
  1057.         if (GetUSBVersion(&usbVersion) == noErr)
  1058.         {
  1059.             if ((usbVersion & 0xffff0000) < 0x01010000)        // Wrong USB version number so do NOT continue
  1060.             {
  1061.                 IF_DEBUG( USBExpertStatus(deviceRef, "\pWrong version of the USB Manager" , 1 ) );
  1062.                                 
  1063.                 IF_DEBUG( USBExpertFatalError(deviceRef, 0, "\pWrong USB Manager version" , 0) );
  1064.                 gConfigured = false;                                // Set the configured flag so we can respond to calls via the dispatch table
  1065.                 gConfigureStatus = kConfigureFailed;        // Flag for client to determine that configuration failed
  1066.                 
  1067.                 return ;
  1068.             }
  1069.         }
  1070.         
  1071.         // Initialize the global data structures
  1072.         BlockZero(&gStorageClassInfo, sizeof(StorageClassInfo));
  1073.         BlockZero(&gInterruptPB, sizeof(StorageClassTransactionPB));
  1074.         BlockZero(&gCommandPB, sizeof(StorageClassTransactionPB));
  1075.         
  1076.         gStorageClassInfo.retryCount =                kStorageRetryCount;
  1077.         gStorageClassInfo.deviceDescriptor =        *deviceDescriptorPtr;        // keep a copy of the device descriptor
  1078.         gStorageClassInfo.pInterfaceDescriptor =    pInterfaceDescriptor;
  1079.         gStorageClassInfo.deviceRef =                    deviceRef;
  1080.         gStorageClassInfo.interfaceRef =                deviceRef;
  1081.         gStorageClassInfo.transDepth =                0;                                    // init Delay Callback Depth
  1082.  
  1083.         InitParamBlock( deviceRef, &gStorageClassInfo.usbPB );
  1084.                 
  1085.         //    Start out at first state
  1086.         if (gStorageClassInfo.pInterfaceDescriptor != NULL)
  1087.         {
  1088.             gStorageClassInfo.usbPB.usbRefcon = kStorageConfigureInterface;
  1089.             IF_DEBUG( USBExpertStatus(deviceRef, "\pStart as interface driver" , 0 ) );
  1090.         }
  1091.         else
  1092.         {
  1093.             gStorageClassInfo.usbPB.usbRefcon = kGetFullConfiguration;
  1094.             IF_DEBUG( USBExpertStatus(deviceRef, "\pStart as device driver" , 0 ) );
  1095.         }
  1096.         
  1097.         gConfigureStatus = kConfigureInProgress;
  1098.         StorageDeviceInitiateConfiguration(&gStorageClassInfo.usbPB);
  1099.     }
  1100. }
  1101.  
  1102.  
  1103. void
  1104. StorageClassDriverFinalize( void )
  1105. {
  1106. OSStatus    status;
  1107.  
  1108.     IF_DEBUG( USBExpertStatus(gStorageClassInfo.deviceRef, "\pStorageClassDriverFinalize." , 0 ) );
  1109.     
  1110.     //
  1111.     // Make sure all pipes are finished with transactions by calling the USBAbortPipeByReference function
  1112.     //
  1113.     status = USBAbortPipeByReference(gStorageClassInfo.deviceRef);                // Control pipe
  1114.     IF_DEBUG( USBExpertStatus(gStorageClassInfo.deviceRef, "\pUSBAbortPipeByReference: Control pipe" , status ) );
  1115.     
  1116.     status = USBAbortPipeByReference(gStorageClassInfo.interruptPipeRef);    // Interrupt pipe
  1117.     IF_DEBUG( USBExpertStatus(gStorageClassInfo.deviceRef, "\pUSBAbortPipeByReference: Interrupt pipe" , status ) );
  1118.     
  1119.     status = USBAbortPipeByReference(gStorageClassInfo.readPipeRef);            // Read pipe
  1120.     IF_DEBUG( USBExpertStatus(gStorageClassInfo.deviceRef, "\pUSBAbortPipeByReference: Read pipe" , status ) );
  1121.     
  1122.     status = USBAbortPipeByReference(gStorageClassInfo.writePipeRef);            // Write pipe
  1123.     IF_DEBUG( USBExpertStatus(gStorageClassInfo.deviceRef, "\pUSBAbortPipeByReference: Write pipe" , status ) );
  1124. }
  1125.  
  1126.  
  1127. OSStatus    
  1128. StorageClassDriverNotifyProc(UInt32    notification, void* pointer)
  1129. {
  1130. #pragma unused (notification, pointer)
  1131. OSStatus status = noErr;
  1132.         
  1133.     IF_DEBUG( USBExpertStatus(gStorageClassInfo.deviceRef, "\pStorageClassDriverNotifyProc. gConfigureStatus: " , gConfigureStatus ) );
  1134.     IF_DEBUG( USBExpertStatus(gStorageClassInfo.deviceRef, "\pStorageClassDriverNotifyProc. gOKToRemoval: " , gOKToRemoval ) );
  1135.     
  1136.     // Don't allow removal if we are busy configuration the interface.
  1137.     if (gConfigureStatus == kConfigureInProgress)
  1138.     {
  1139.         status = kUSBDeviceBusy;
  1140.     }
  1141.     
  1142.     // Don't allow removal until the Shim says it's ok
  1143.     if (gOKToRemoval == false)
  1144.     {
  1145.         status = kUSBDeviceBusy;
  1146.     }
  1147.     
  1148.     return (status);
  1149. }
  1150.